package main

import (
	"errors"
	"fmt"
)

type MyError struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
}

func (error *MyError) Error() string {
	return fmt.Sprintf("Code: %d, Message: %s", error.Code, error.Message)
}

// 还可以通过errors包快速创建自定义错误。
var myerror error = errors.New("自定义错误类型对象")

func getOneError(num int) error {
	var result error
	if num == 1 {
		result = fmt.Errorf("返回一个错误 %w", myerror)
	} else if num == 2 {
		result = &MyError{Code: 404, Message: "自定义结构体充当错误类型对象"}
	}
	return result
}

//Go 语言的错误处理采用显式返回错误的方式，而非传统的异常处理机制。这种设计使代码逻辑更清晰，便于开发者在编译时或运行时明确处理错误。
/*
Go 的错误处理主要围绕以下机制展开：

    error 接口：标准的错误表示。
    显式返回值：通过函数的返回值返回错误。
    自定义错误：可以通过标准库或自定义的方式创建错误。
    panic 和 recover：处理不可恢复的严重错误。

	error 类型是一个接口类型，这是它的定义：
	type error interface {
		Error() string
	}
	任何实现了 Error() 方法的类型都可以作为错误。
*/
func main() {
	fmt.Printf("详细的错误信息 %+v \n", myerror.Error())
	//检查某个错误是否是特定错误或由该错误包装而成。errors.Is
	if errors.Is(getOneError(1), myerror) {
		fmt.Printf("获得的错误是我自定义的错误 \n")
	}
	//将错误转换为特定类型以便进一步处理。errors.As
	var myError *MyError
	if errors.As(getOneError(2), &myError) {
		fmt.Printf("转换成功，错误信息填入了myError对象中  \n")
	}
	/*
		panic:手动导致程序崩溃并输出堆栈信息。
			发生panic后，程序会从调用panic的函数位置或发生panic的地方立即返回，逐层向上执行函数的defer语句，然后逐层打印函数调用堆栈，直到被recover捕获或运行到最外层函数。
			panic不但可以在函数正常流程中抛出，在defer逻辑里也可以再次调用panic或抛出panic。defer里面的panic能够被后续执行的defer捕获。
			多个panic指挥捕获最后一个触发的panic
		recover:捕获 panic，避免程序崩溃。
			recover用来捕获panic，阻止panic继续向上传递。recover()和defer一起使用，但是defer只有在后面的函数体内直接被调用才能捕获panic来终止异常，否则返回nil，异常继续向外传递。
		defer:正常代码顺序执行完后，开始倒序执行defer修饰的函数；正常代码执行过程出现panic，从panic位置倒序执行defer
	*/
	fmt.Println("外层开始")
	defer func() {
		fmt.Println("f_外层defer_recoverBefore_before")
	}()
	fmt.Println("e_外层异常before")
	defer func() {
		fmt.Println("d_外层recoverBefore")
		if err := recover(); err != nil {
			fmt.Printf("%#v-%#v\n", "d_外层recover执行_", err)
		} else {
			fmt.Println("外层没做啥事")
		}
		fmt.Println("d_外层recoverAfter")
	}()
	fmt.Println("c_外层异常before")
	defer func() {
		fmt.Println("b_外层defer_recoverAfter_after")
	}()
	fmt.Println("a_外层异常before")
	f() //内层触发panic，如果内层没有recover，那么此行后面代码不会执行
	fmt.Println("a_外层异常after")
	defer func() { //一旦内层进行了recover，那么defer修饰的外层函数中，这个函数会最先开始执行
		fmt.Println("b_外层defer_外层异常after_after")
	}()
	fmt.Println("外层结束")
}

func f() {
	fmt.Println("内层开始")
	defer func() {
		fmt.Println("6_defer_recoverBefore_before")
	}()
	fmt.Println("5_内层异常before")
	defer func() {
		fmt.Println("4_recoverBefore")
		if err := recover(); err != nil {
			fmt.Printf("%#v-%#v\n", "4_recover执行_", err) // 这里err就是panic传入的内容
		}
		fmt.Println("4_recoverAfter")
	}()
	fmt.Println("3_内层异常before")
	defer func() {
		fmt.Println("2_defer_recoverAfter_after")
	}()
	fmt.Println("1_内层异常before")
	panic("异常信息") //触发panic，内层无论是否recover，这行后面的代码都不会执行
	fmt.Println("1_内层异常after")
	defer func() {
		fmt.Println("2_defer_内层异常after_after")
	}()
	fmt.Println("内层结束")
}
